Mysql数据库事务的4个特性
- 原子性(Atomicity)
原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。 - 一致性(Consistency)
事务前后数据的完整性必须保持一致 - 隔离性(Isolation)
事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离 - 持久性(Durability)
持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响
Mysql的事务隔离级别,以及每种级别下会产生的问题和对问题的理解
Read uncommitted:隔离性最差的一种方式,违反了为数据库事务的隔离性,事务A读取了事务B对数据C修改后但未提交的内容,即事务B还未提交,还在执行过程中;
在这种级别下会出现脏读
Read Committed(读已提交/不可重复读):违反了数据库事务的一致性,是指在同一个事务内,对同一个数据集合的连续读取两次,读 到的数据是不一样的。也就是说,Read Committed模式下,一个事务既可以感知另一个事务添加新数据,也能感知这个事务对数据的修改。
RC模式,避免了脏读,但是可能会造成不可重复读。
select时会受update的影响出现在同一个事务中两次读到数据不一致,主要体现在数据行的内容不一致,
Mysql使用了Record-Lock,同一时刻只允许一个事务对同一数据修改,解决了脏读Repeatable Read(可重读): MySQL默认级别,解决了不可重复读,但会出现幻读的情况。每个事务独立执行,如果一个事务添加了新数据,并已提交完毕;另外一个正在执行的事务能看到新加的数据。但如果一个事务是修改数据后提交完毕,另一个正在执行的事务是看不到这种修改的。在新增加数据的情况下,破环的事务了的隔离性。
在RR这种隔离级别下会出一幻读
幻读是select会受insert或delete的影响下会出现幻读行,体现在同事个事务中连续两次读到的数量不一致
但是mysql在RR级别下,通过Next-Key Lock(Rercord-Lock+ Gap-Lock)算法,避免了不可重复读的现象。所以InnoDB存储引擎在RR级别下就达到了3度的隔离。
Serializable(串行化执行):最高隔离性级别。同时执行的两个事务完全隔离,每个事务有独立的运行空间。主要应用于InnoDB存储引擎的分布式事务,而且分布式事务中要求数据库的隔离级别必须为Serializable
Mysql的过引方法有哪些?
B+树和HASH
为什么不使用B树,要使用B+树
B+树是二次查询树的优化,有自我调整平衡的能力和节点顺序能力,同时支持范围查询
InnoDB和MyISAM区别
- innodb支持事务MyISAM不支持事务
- MyISAM锁的粒度是表级,而InnoDB支持行级锁定
- InnoDB数据的存储使用了聚集的方式,表的数据存储是按主键的顺序进行存放,如果没有显示指定主键,引擎会为每一行生成一个6字节的ROWID作为主键,索引文件就是数据文件,
- MyISAM适合存储报表的数据,无事务,简单查询,InnoDB适用于有事务处理的情况
- 主索引的区别,InnoDB是聚集索引数据文件本身就是索引文件。而MyISAM是非聚集索引,索引文件(MYI)和数据文件(MYD)是分离的,索引文件仅保存数据记录的地址
- 辅助索引的区别:InnoDB的辅助索引data域存储相应记录主键的值而不是地址。而MyISAM的辅助索引和主索引没有多大区别,只是主索引要求key是唯一的,而辅助索引的key可以重复
数据库如何解决事务冲突
大多数数据库使用加锁和数据版本管理两种策略,它们是两种不同的思想:
锁分为乐观锁(optimistic locking)与悲观锁(pessimistic locking)
悲观锁(读写互相阻塞)
乐观锁(写写阻塞)
数据版本管理
一种乐观锁的实现,所有的事务都可以同时修改相同的数据,每个事务都持有所有数据的一个拷贝,最终只会有一个事务的修改会提交成功持久化,其它事务将会回滚,这种方式因为读写不会相互阻塞,所以带来了性能上的提升,这处方式缺点就是相同的数据会存在多份,所以需要巨大的磁盘空间开销如何判断数据库进入了死锁
依据lock manager的哈希表,能画出一个依赖关系图(类似上面的截图)。如果在图中出现了环路,即意味着出现了死锁。检查是否出现环路是非常耗时的,因为依赖关系图的数据量通常很庞大;所以,一般采用更简单的方法:判断是否超时。如果事务申请的锁未在指定的超时时间内分配,则认为事务进入了死锁。进入死锁之后如何处理?
出现死锁时,Lock manger将选择其中一个事务回滚以解除死锁状态。选择哪一个事务回滚,这是个很复杂的问题,要考虑以下方面:
- 回滚涉及数据量最小的事务(造成混滚的代价最小)
- 回滚最新提交的事务(因为其它事务等待的时间更长)
- 回滚耗时更短的事务(避免长时间等待,线程饿死
- 即使回滚,又有多少其它事务会受此回滚的影响?
索引为什么可以提高查询效率?
Mysql存储是根据事务将依次次数据持久化在磁盘上,我们使用时候的不是按写入顺序读取,所以在我们使用数据时候,会产生很多随机IO磁盘,通过索引,将数据通过一定的规则整理,将随机读变成顺序度,从而减少磁盘IO,提升查询效率
MySQL为何将节点大小设置为页的整数倍?
局部预读性原理告诉我们,当计算机访问一个地址的数据的时候,与其相邻的数据也会很快被访问到。如果一次IO读取的数据我们称之为一页(page)。具体一页有多大数据跟操作系统有关,一般为4k或8k。
MySQL巧妙利用了磁盘预读原理,将一个节点的大小设为等于一个页,这样每个节点只需要一次I/O就可以完全载入。为了达到这个目的,每次新建节点时,直接申请一个页的空间,这样就保证一个节点物理上也存储在一个页里,加之计算机存储分配都是按页对齐的,就实现了读取一个节点只需一次I/O。假设B+Tree的高度为h,一次检索最多需要h-1次I/O(根节点常驻内存),复杂度O(h) = O(logmN)。实际应用场景中,M通常较大,常常超过100,因此树的高度一般都比较小,通常不超过3。
磁盘块的大小也就是一个数据页的大小,是固定的,如果数据项占的空间越小,数据项的数量越多,树的高度越低。这就是为什么每个数据项,即索引字段要尽量的小,比如int占4字节,要比bigint8字节少一半。
当索引的KEY越小(字段越小),一页可以存储的索引越多,一次载入到内存中的数据也就越多,这也解释了为什么B+树,要求把真实的数据放到叶子节点中,而不是内层节点,一旦放到内层节点,一次读到的索引会大幅度减少,导致频繁的IO,另一方面也会导致树的高度增加。
Mysql中的联合索引
非统计查询时必须符合最左原则
如果是统计操作,并且是覆盖索引的,则优化器会选择走联合索引,通过索引覆盖来优化count(*)
优化器选择不使用索引的情况?
如果表字段X存在辅助索引,而在执行SQL, select * from table1 where x>400
时,在查看扫行计划时如果未选择辅助索引,这种情况下多发生于范围查找、join连接操作,原因如下:
- 如果被查询出来的数据量占整张表的20%左右时,可能会导致优化器放弃辅助索引,而改为聚集索引查询,因为如果使用辅助索引,会导致大量的随机读 ,改为聚集索引,使用顺序读性能远远高于随机读。
- 如果查出来的数据量较少时,优化器是会选择辅助索引
Mysql5.6的几个优化
MRR :目的就是减少磁盘的随机访问,并且将随机访问转化为较为顺序的数据访问,优化适合用于range , ref ,eq-ref
主要原理就是,将辅助索引查询到的数据放于缓存中,对缓存中的数据根据RowID进行排序,然后用较为顺序的方式来访问数据,这样就减少了随机读 ,并且减少了缓冲页中被替换的次数.
此外MRR还可以将某些范围查询拆分为键值对,来进行批量数据查询,这样的好处就是可以在拆分过程中,直接过滤掉一部分不符合条件的数据。
执行计划的Extra中会看到using MRR
ICP : 索引条件下压,就是将where部分的过滤操作,下沉到存储引擎层,在某些查询下,可以大大减少返回上层的数据,从而提高整体性能。 优化适用于range , ref , eq_ref , ref_or_null
,执行计划Extra中会看到Using index condition
mysql中的hash索引
innodb中冲突机制采用链表方式,哈希函数采用除法散列方式,Hash索引只能用来搜索等值查询,无法处理范围查询,所以使用场景比较少。
mysql中的锁
共享锁(S):是Share的缩写,共享锁的锁粒度是行或者元组(多行)。一个事务获得了共享锁之后,就可以对锁定范围内的数据进行读操作。
排他锁(X):是eXclusive的缩写,排他锁的粒度和共享锁一样,也是行或者元组。一个事务获得排他锁之后,就可以对锁定范围内的数据执行insert/delete/update操作。
意向锁:意向锁是一种表级锁,锁的粒度是整张表。分为意向共享锁(IS)和意向排他锁(IX)
意向锁的存在价值在于在定位到特定的行所持有的锁之前,提供一种更粗粒度的锁,可以理解为一种快速失败的机制,可以大大节约引擎对于锁的定位和处理的性能,因为在存储引擎内部,锁是由一块独立的数据结构维护的,锁的数量直接决定了内存的消耗和并发性能。例如,事务A对表t的某些行修改(DML通常会产生X锁),需要对t加上意向排它锁,在A事务完成之前,B事务来一个全表操作(alter table等),此时直接在表级别的意向排它锁就能告诉B需要等待(因为t上有意向锁),而不需要再去行级别判断。
兼容:SS、IS和IS、IS和IX、IX和IX
意向锁之间彼此不会冲突,因为它们都只是“意向”,所以是可以兼容的。在加行锁之前会使用意向锁判断是否冲突;
不兼容:除了IX和IX只要存在任意一个排它锁都不会兼容
MYSQL执行计划的中的TYPE有哪些
效率由好到差
- system : 表里面仅一行记录
- const :表示通过索引一次就找到,表中有多行记录,但是最多只有匹配到一行记录
- eq_ref: 使用主键和唯一索引,只有一行记录匹配到
- ref: 只使用到普通索引,没有使用主键和唯一 索引
- ref_or_null: 类似 ref,不同的是mysql会在检索的时候额外的搜索包含null 值的记录
- index_merge :索引合并
- unique_subquery:主键子查询
- index_subquery:非主键子查询
- range :使用范围查询
- index: 使用索引
- all :全表扫描
INNODB和MYISAM中的表存储
INNODB
- 独立表空间下: .frm 、 .ibd
- 共享表空间下: .frm 、.idbdata1
- 分区下: .frm 、.par、 p0.ibd 、 p1.ibd 、 ….. 、pn.ibd 。只有在独立表空间打开时才可以做分区(innodb_file_per_table =1 )
MYISAM
- 无分区:.frm 、 .myd 、.myi
- 有分区:.frm、 .par 、.myd(1-n) 、myi(1-n)
MYSQL的分区方式
- RANGE分区:根据年或者主键等分区
- LIST分区:适合枚举区分,值固定
- HASH分区:预先确认分区数,如果确保数据可以在预先确定的分区中可以平均分布,可以考虑
- KEY分区:与HASH分区类似,但它的KEY可以不是整数
MYSQL中的组合索引
适合单独查询返回结果很多,组合查询返回很少数据
组合索引使用时要满足最左原则(驱动索引)
仅存在等值查询时,组合索引顺序不影响性能
如果存在等值+范围时,建立索引时先等值后范围,等值列前置
组合索引的排序,使用时要与建立时的顺序一致,全正或全负